home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / ip / ppp / mac / macppp1.1.3-src.hqx / MacPPP1.1.3-src / io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-09  |  21.3 KB  |  804 lines

  1. /*  io.c
  2.  *    I/O routines for MacPPP
  3.  *
  4.  * Copyright 1992-1993 Merit Network, Inc. and The Regents of the
  5.  *  University of Michigan.  Usage of this source code is restricted
  6.  *  to non-profit, non-commercial purposes.  The source is provided
  7.  *  "as-is", without warranty.
  8.  */
  9. #include "ppp.h"
  10.  
  11. /* macro to calculate new fcs */
  12. #define pppfcs(fcs, c)        ((fcs >> 8) ^ lap->fcstab[(fcs ^ c) & 0x00ff])
  13.  
  14. /*
  15. *    Pass the completed IP packet up to the IP layer.
  16. */
  17. void    rcvip(register LapInfo *lap, struct bufheader *bufptr)
  18. {
  19. long        oldA5;
  20.  
  21.     if (lap->rds.rdsparm.lnb.lnb_ptr != nil) { /* MacTCP doesn't always call ReadRest */
  22.         /* DebugStr("\pIPPH not ready"); */
  23.         release(lap->rds.rdsparm.lnb.lnb_ptr);    /* free un-copied data */
  24.     }
  25.     
  26.     lap->idle_timer = 0;    /* clear idle timer */
  27.     tcp_window_fix(lap, bufptr);    /* TCP window hack */
  28.     
  29.     lap->rds.laphdr.ptr = nil;
  30.     lap->rds.laphdr.length = 0;
  31.     lap->rds.lapBroadcast = FALSE;
  32.     lap->rds.lap = lap;
  33.     lap->rds.ph_rp = (ProcPtr) readpkt;    /* set up ptr's to */
  34.     lap->rds.ph_rr = (ProcPtr) readrest;    /* mysterious rtn's */
  35.     lap->rds.rdsparm.lnb.lnb_ptr = bufptr;    /* ptr to packet */
  36.     lap->rds.ph_bytesleft =  bufptr->length;    /* length of packet */
  37.  
  38.     /* pass pkt to IP layer in a rdStruct */
  39.     if (lap->ip_ph != nil) {
  40.         oldA5 = seta5((long)lap->ipGlobals);    /* setup apps A5 */
  41.         (*(lap->ip_ph))(&(lap->rds));
  42.         seta5(oldA5);                    /* restore old A5 */
  43.         }
  44.     else
  45.         PPP_DEBUG_CHECKS("\pNo ip_ph to call!");
  46. }
  47.  
  48. OSErr    readpkt(struct rdStruct *rds, Ptr bufp, long buflen)
  49. {
  50. #ifdef LOG
  51.     log(GetLAPPtr(),0x3, (int) TickCount(),(int)( rds->rdsparm.lnb.lnb_ptr), (int) buflen);
  52. #endif
  53.     /* 
  54.     *    It's against the rules to have ReadPacket read in the remainder
  55.     *    of the packet. You have to call ReadRest for that 
  56.     *    Too bad nobody plays by the rules. ReadPacket can't return an error
  57.     *    if bytesleft exactly equals buflen, or else the higher layer gets
  58.     *    an error on a packet with 0 bytes of data, which breaks everything.
  59.     */
  60.     if (rds->ph_bytesleft >= buflen) {    /* will this buffer fill up? */
  61.         yankbuf(rds->rdsparm.lnb.lnb_ptr, bufp,(b_16) buflen);    /* copy data */
  62.         rds->ph_bytesleft -= buflen;    /* update len */
  63.         return    (0);        /* buffer has data */
  64.     }
  65.     return (-1);        /* call ReadRest instead */
  66. }
  67. /*
  68. *    ReadRest is called to read the remainder of a packet.  It must be 
  69. *    called exactly once per packet.
  70. */
  71. long    readrest(register struct rdStruct *rds, Ptr bufp, long buflen)
  72. {
  73.     long     rc;
  74. #ifdef LOG
  75.     log(GetLAPPtr(),0x4, (int) TickCount(),(int)( rds->rdsparm.lnb.lnb_ptr), (int) buflen);
  76. #endif
  77.     if (rds->ph_bytesleft > buflen) {    /* packet won't fit Truncate */
  78.         yankbuf(rds->rdsparm.lnb.lnb_ptr, bufp,(b_16) buflen);
  79.         rds->ph_bytesleft -= buflen;    /* update # of bytes truncated */
  80.         rc = -(rds->ph_bytesleft);
  81.     } else {
  82.         yankbuf(rds->rdsparm.lnb.lnb_ptr, bufp, (b_16) rds->ph_bytesleft);
  83.         rc = buflen - rds->ph_bytesleft;
  84.         rds->ph_bytesleft = 0;    /* the entire packet is copied */
  85.     }
  86.     release(rds->rdsparm.lnb.lnb_ptr);
  87.     rds->rdsparm.lnb.lnb_ptr = nil;
  88.     return rc;    /* return value */
  89. }
  90.  
  91. /*
  92.  * ProcFrame - process a PPP frame in an MBUF
  93.  */
  94.  
  95. void
  96. ProcFrame(register LapInfo *lap, register struct bufheader *bufptr)
  97. {
  98.     register b_16    proto;
  99.     register int    RecvByte;
  100.     
  101.     /* pull off header */
  102.     if ((RecvByte = yankbyte(bufptr)) < 0)
  103.         goto error;
  104.  
  105.     if (RecvByte == HDLC_ALL_ADDR) {
  106.         if ((RecvByte = yankbyte(bufptr)) < 0)
  107.             goto error;
  108.  
  109.         if (RecvByte == HDLC_UI) {
  110.             if ((RecvByte = yankbyte(bufptr)) < 0)
  111.                 goto error;
  112.  
  113.             if ((RecvByte & 0x01) != 0) {
  114.                 proto = RecvByte;
  115.             } else {
  116.                 proto = RecvByte << 8;
  117.  
  118.                 if ((RecvByte = yankbyte(bufptr)) < 0)
  119.                     goto no_error;
  120.  
  121.                 if ((RecvByte & 0x01) == 0)
  122.                     goto error;
  123.  
  124.                 proto += RecvByte;
  125.             }
  126.         } else {
  127.             goto error;
  128.         }
  129.     } else {
  130.         if (RecvByte & 0x01) {
  131.             proto = RecvByte;
  132.         } else {
  133.             proto = RecvByte << 8;
  134.  
  135.             if ((RecvByte = yankbyte(bufptr)) < 0)
  136.                 goto no_error;
  137.  
  138.             proto += RecvByte;
  139.         }
  140.     }
  141.  
  142.     /* handle frame */
  143.  
  144.     switch (proto) {
  145.     case PPP_IP_PROTOCOL:
  146.         if (lap->ppp_fsm[IPcp].state != fsmOPENED) {
  147.             PPP_DEBUG_CHECKS("\pnot open for IP traffic");
  148.             goto in_error;
  149.         }
  150.         rcvip(lap, bufptr);
  151.         break;
  152.  
  153.     case PPP_VJ_COMP_PROTOCOL:
  154.         if (lap->ppp_fsm[IPcp].state != fsmOPENED) {
  155.             PPP_DEBUG_CHECKS("\pnot open for Compressed TCP/IP traffic");
  156.             goto in_error;
  157.         }
  158.         if (!(lap->ipcp_i.local.work_negotiate & IPCP_N_COMPRESS)) {
  159.             PPP_DEBUG_CHECKS("\pCompressed TCP/IP not enabled");
  160.             goto in_error;
  161.         }
  162.         if (slhc_uncompress(lap, bufptr) <= 0) {
  163.             PPP_DEBUG_CHECKS("\pCompressed TCP/IP packet error");
  164.             goto in_error;
  165.         }
  166.         rcvip(lap, bufptr);
  167.         break;
  168.  
  169.     case PPP_VJ_UNCOMP_PROTOCOL:
  170.         if (lap->ppp_fsm[IPcp].state != fsmOPENED) {
  171.             PPP_DEBUG_CHECKS("\pnot open for Uncompressed TCP/IP traffic");
  172.             goto in_error;
  173.         }
  174.         if (!(lap->ipcp_i.local.work_negotiate & IPCP_N_COMPRESS)) {
  175.             PPP_DEBUG_CHECKS("\pUncompressed TCP/IP not enabled");
  176.             goto in_error;
  177.         }
  178.         if (slhc_remember(lap, bufptr) <= 0) {
  179.             PPP_DEBUG_CHECKS("\pUncompressed TCP/IP packet error");
  180.             goto in_error;
  181.         }
  182.         rcvip(lap, bufptr);
  183.         break;
  184.  
  185.     case PPP_LCP_PROTOCOL:
  186.         fsm_proc(&(lap->ppp_fsm[Lcp]), bufptr);
  187.         break;
  188.  
  189.     case PPP_PAP_PROTOCOL:
  190.         if (lap->ppp_phase != pppAUTHENTICATE
  191.             && lap->ppp_phase != pppNETWORK) {
  192.             PPP_DEBUG_CHECKS("\pNot ready for Authentication");
  193.             goto in_error;
  194.         }
  195.         pap_proc(&(lap->ppp_fsm[Pap]), bufptr);
  196.         break;
  197.  
  198.     case PPP_IPCP_PROTOCOL:
  199.         if (lap->ppp_phase != pppNETWORK) {
  200.             PPP_DEBUG_CHECKS("\pNot ready for IPCP traffic");
  201.             goto in_error;
  202.         }
  203.         fsm_proc(&(lap->ppp_fsm[IPcp]), bufptr);
  204.         break;
  205.  
  206.     default:
  207.         lap->InUnknown++;                /* count unknown protocol */
  208.         if (lap->ppp_fsm[Lcp].state == fsmOPENED) {
  209.             makeroom(bufptr, 2);
  210.             put16(bufptr->dataptr, proto);        /* put protocol field back on */
  211.             fsm_send(&(lap->ppp_fsm[Lcp]), PROT_REJ, 0, bufptr); /* send protocol reject */
  212.         } else    
  213.             release(bufptr);
  214.         break;
  215.     }
  216.     return;
  217.  
  218.     /* finish up */
  219. in_error:
  220.     lap->InError++;
  221.     goto no_error;
  222. error:
  223.     lap->InHeader++;
  224.     PPP_DEBUG_CHECKS("\pPPP header error");
  225. no_error:
  226.     release(bufptr);        /* release the buffer */
  227.     return;
  228. }
  229.  
  230. long
  231. GetQSize(register LapInfo *lap) {
  232.     register long qcount;
  233.  
  234.     lap->stat_pb.csCode = 2;        /* call SerGetBuf routine */
  235.     asm {
  236.         lea    lap->stat_pb,a0
  237.         _PBStatus    IMMED
  238.     }    
  239.     qcount =  *( (long *) lap->stat_pb.csParam);
  240.     if (qcount > RXBUFSIZE)
  241.         qcount = RXBUFSIZE;
  242.     lap->r_iopb.iop.ioReqCount = qcount;
  243.     return qcount;
  244. }
  245.  
  246. void
  247. ProcRcvPPP(void){
  248.  
  249.     register LapInfo    *lap;
  250.     register long        qcount;
  251.     struct TMprocess    *tmprocp;
  252.  
  253.     asm {
  254.         move.l    a1,tmprocp
  255.     }
  256.     lap = tmprocp->tmsavptr.lap;
  257.     if (GetQSize(lap) == 0)
  258.         PrimeTime(&(lap->rxp_task), 5L); /* no data, try again in 5 ms */
  259.     else {
  260.         asm {
  261.             lea lap->r_iopb.iop,a0
  262.             _PBRead    ASYNC                /* read the data */
  263.         }
  264.     }
  265. }
  266.  
  267. void
  268. SerReadDone(void){
  269.  
  270.     typedef enum
  271.     {
  272.         c_Flag,            /* PPP opening/closing flag */
  273.         c_Escape,        /* PPP escape char */
  274.         c_Normal,        /* A normal data character */
  275.         c_Ignore,        /* Character to be ignored */
  276.         c_Error            /* Errored char received */
  277.     }    class_t;
  278.  
  279.     register LapInfo    *lap;
  280.     sdiopb        *pb;
  281.     struct bufheader    *tempbuf;
  282.     register    int        *cntptr;
  283.     char                *dataptr;
  284.     register    char    *rbufptr;
  285.     register    char    *rbufend;
  286.     register class_t    RecvClass;
  287.     register b_8        RecvByte;
  288.     register HDLCState    RecvState;
  289.     register b_8        StatusByte;
  290.     long                qcount;
  291.     OSErr                rc;
  292.     
  293.     asm {
  294.         move.l a0,pb             ; set up paramblkptr
  295.     };
  296.     
  297.     lap = pb->lap;
  298.  
  299.     if ((rc = pb->iop.ioResult) != noErr) {
  300.         lap->readerr++;
  301.         lap->lasterr = rc;
  302.         PPP_DEBUG_CHECKS("\pSerial driver rx. error");
  303.         goto rcvexit;
  304.     }
  305.     qcount = pb->iop.ioActCount;
  306.  
  307.     lap->InRxOctetCount += qcount;        /* count the octets */
  308.     rbufptr = lap->rxbuf;
  309.     rbufend = rbufptr + qcount;
  310.     dataptr = lap->bufptr->dataptr;        /* pointer to start of data in mbuf */
  311.     cntptr = &(lap->bufptr->length);
  312.     while (rbufptr < rbufend) {
  313.         RecvByte = *rbufptr++;
  314.         RecvState = lap->read_state;
  315.  
  316.         if (lap->bufptr == nil) {
  317.             if ( (lap->bufptr = getbuffer() ) != nil ) {
  318.                 dataptr = lap->rddata = lap->bufptr->dataptr;
  319.                 cntptr = &(lap->bufptr->length);
  320.             } else {
  321.                 PPP_DEBUG_CHECKS("\pNo rbufs");
  322.                 goto rcvexit;
  323.             }
  324.         }
  325.         /* figure equivalence class of input char/err */
  326.         if (RecvByte == PPP_FLAG)
  327.             RecvClass = c_Flag;
  328.         else if (RecvByte == PPP_ESCAPE)
  329.             RecvClass = c_Escape;
  330.         else if ((RecvByte & 0xE0) != 0)
  331.             RecvClass = c_Normal;
  332.         else {
  333.             if (((1L << RecvByte) & lap->PPP_RecvACM) != 0) {
  334.                 RecvClass = c_Ignore;
  335.             } else
  336.                 RecvClass = c_Normal;
  337.         }
  338.  
  339.         /*
  340.          * "I feel the need, the need for speed" The C switch()
  341.          * statement is too slow for use here, so we just use a
  342.          * carefully organized if...elseif...elseif... statement to
  343.          * optimize this routine for speed.  --ejs
  344.          */
  345.         /* handle receive states
  346.          * Taken from KA9Q and re-arranged for better performance
  347.          * also changed to if else style per ejs suggestion.  --ljb
  348.          */
  349.         if (RecvState == s_Data) {
  350.             if (RecvClass == c_Normal) {
  351.                 if ((*cntptr)++ <= PPP_BUFSIZE) {
  352.                     lap->RecvFCS = pppfcs(lap->RecvFCS, RecvByte);
  353.                     *(lap->rddata)++ = RecvByte;
  354.                 } else {
  355.                     (*cntptr)--;
  356.                     lap->InFrameOvr++;
  357.                     lap->read_state = s_Idle;
  358.                 }
  359.             }
  360.             else if (RecvClass == c_Escape)
  361.                 lap->read_state = s_Escape;
  362.             else if (RecvClass == c_Flag) {
  363.                 if (lap->RecvFCS == FCS_TERM) {
  364.                     lap->RecvFCS = FCS_INIT;  /* reset FCS */
  365.                     lap->InOpenFlag++;        /* count good frame */
  366.                     tempbuf = lap->bufptr;        /* get pointer to current mbuf */
  367.                                             /* must make copy due to possible re-entrancy */
  368.                     lap->bufptr = nil;        /* need new buffer next time */
  369.                     tempbuf->length -= 2;        /* trim FCS bytes */
  370.                     ProcFrame(lap, tempbuf);    /* process the PPP frame */
  371.                 } else if (*cntptr > 0) {
  372.                     PPP_DEBUG_CHECKS("\pGot a bad FCS");
  373.                     lap->InCheckSeq++;
  374.                     *cntptr = 0;
  375.                     lap->rddata = dataptr;
  376.                     lap->RecvFCS = FCS_INIT;
  377.                     lap->stat_pb.csCode = 8;        /* call SerStatus routine */
  378.                     asm {
  379.                         lea    lap->stat_pb,a0
  380.                         _PBStatus    IMMED
  381.                     }
  382.                     StatusByte = *( (b_8 *) lap->stat_pb.csParam);
  383.                     if (StatusByte & swOverrunErr)
  384.                         lap->InSoftOvr++;
  385.                     if (StatusByte & hwOverrunErr)
  386.                         lap->InHardOvr++;
  387.                     if (StatusByte & framingErr)
  388.                         lap->InFramingErr++;
  389.                 }
  390.             }
  391.         }
  392.         else if (RecvState == s_Escape) {
  393.             if (RecvClass == c_Normal) {
  394.                 if (*cntptr <= PPP_BUFSIZE) {
  395.                     RecvByte ^= 0x20;
  396.                     lap->RecvFCS = pppfcs(lap->RecvFCS, RecvByte);
  397.                     *(lap->rddata)++ = RecvByte;
  398.                     (*cntptr)++;
  399.                     lap->read_state = s_Data;
  400.                 } else {
  401.                     lap->InFrameOvr++;
  402.                     lap->read_state = s_Idle;
  403.                 }
  404.             }
  405.             else if (RecvClass == c_Flag)
  406.                 lap->read_state = s_Idle;
  407.         }
  408.         else if (RecvState == s_Idle) {
  409.             if (RecvClass == c_Flag) {
  410.                 lap->RecvFCS = FCS_INIT;
  411.                 lap->read_state = s_Data;
  412.                 lap->rddata = dataptr;
  413.                 *cntptr = 0;
  414.             } else 
  415.                 lap->InIdleToss++;
  416.         }
  417.         else if (RecvState == s_Init) {
  418.             RecvByte &= 0x7f;        /* clear high bit */
  419.             if (!lap->term_mode || ( RecvByte != 0x0a && RecvByte != 0x08) ) {
  420.                 if (*cntptr >= PPP_BUFSIZE) {
  421.                     lap->rddata = dataptr;    /* wrap around */
  422.                     *cntptr = 0;
  423.                 }
  424.                 *(lap->rddata)++ = RecvByte;    /* buffer and hi bit */
  425.                 (*cntptr)++;
  426.             } else if (RecvByte == 0x08 && *cntptr > 0) {
  427.                 (*cntptr)--;    /* decrement counter */
  428.                 lap->rddata--;    /* decrement pointer */
  429.             }
  430.         }
  431.     }
  432.     
  433. rcvexit:
  434.  
  435.     PrimeTime(&(lap->rxp_task), 2L);
  436. }
  437.  
  438. /* queue a frame to transmitted */
  439. OSErr QueueFrame (LapInfo *lap, struct bufheader *bufptr, struct ipbuf *ipbp)
  440. {
  441.     PPPiopb    *pb;
  442.     short    sreg;
  443.     
  444.        /* try to get a free transmit queue element */
  445.     
  446.     if ((pb = (PPPiopb *)lap->pppbq.qHead) != nil) {
  447.         Dequeue(pb, &(lap->pppbq));
  448.     }
  449.     if (pb != nil) {
  450.         if ((pb->ipbuf = ipbp) != nil) {    /* check if from MacTCP */
  451. #ifdef LOG
  452.     log(lap, 0x1,(int) TickCount(),(int) ipbp, (int)ipbp->iop.ioCompletion );
  453. #endif
  454.             ipbp->iop.ioResult = inProgress; /* mark i/o as async */
  455.         }
  456.         pb->bufptr = bufptr;                /* point to mbuf (if available) */
  457.         Enqueue(pb, &(lap->out_q));            /* queue for xmit */
  458.     } else {
  459.         /* we're out of Q elements (very bad) */
  460.         lap->outofiopbs++;
  461.         PPP_DEBUG_CHECKS("\pOut of ioParam blocks");
  462.         IOCompleted(lap, ipbp);
  463.         return(noErr);
  464.     }
  465.                     
  466.         /* Prime transmit task (if not already) */
  467.     sreg = set_sr(0x2100);    /* Disable timer Ints */
  468.     if (!(lap->txp_task.atm.qType & TASK_QUEUED))    /* check if task in q */
  469.         PrimeTime(&(lap->txp_task), 0L);
  470.     set_sr(sreg);        /* Reset ints */ 
  471.  
  472.     return(noErr);
  473. }
  474.  
  475. void IOCompleted(LapInfo *lap, struct ipbuf *ipbp)
  476. {
  477. long    oldA5;
  478.  
  479. #ifdef LOG
  480.     log(lap, 0x2, (int) TickCount(), (int) ipbp, 0);
  481. #endif
  482.     
  483.     if (ipbp->iop.ioCompletion != nil) {    /* check if completion routine */
  484.         oldA5 = seta5((long)lap->ipGlobals);
  485.         ipbp->iop.ioResult = noErr;    /* always return no error */
  486.         asm {
  487.             movea.l    ipbp,a0        /* set pointer to iop */
  488.             move.l    noErr,d0    /* result code */
  489.             move.l    a0,-(a7)
  490.             movea.l    IOParam.ioCompletion(a0),a1    /* completion routine*/
  491.             tst.w    d0
  492.             jsr        (a1)
  493.             addq.l    #4,a7
  494.         }
  495.         seta5(oldA5);
  496.     }
  497. }
  498.  
  499. void IOfinish(register LapInfo *lap, PPPiopb *pb)
  500. {
  501.     struct ipbuf *ipbp = pb->ipbuf;
  502.  
  503.     Enqueue(pb, &(lap->pppbq));        /* give back iopb to pool */
  504.     IOCompleted(lap, ipbp);        /* call the completion routine */
  505. }
  506.  
  507. PPPiopb *Getxmitpb(LapInfo *lap)
  508. {
  509.     PPPiopb                *pb;
  510.     struct bufheader    *bufptr;
  511.     struct ipbuf        *ipb;
  512.     struct wdsEntry        *wdsp;
  513.     char                *datap;
  514.     int                    n, protocol = PPP_IP_PROTOCOL;
  515.     short                sr;
  516.     b_16                proto;
  517.     
  518.     if ((pb = (PPPiopb *)lap->out_q.qHead) != nil)
  519.         Dequeue(pb, &(lap->out_q));        /* Dequeue a xmit buffer */
  520.     else
  521.         return nil;
  522.  
  523.     if    (pb->bufptr != nil)    {    /* check if from MacTCP or LAP */
  524.         if (pb->ipbuf != nil) { /* special case for LCP echos */
  525.             pb->ipbuf = nil;
  526.             if ((bufptr = getbuffer()) == nil)    /* get a buffer */
  527.                 return nil;
  528.             bufptr->length = pb->bufptr->length;
  529.             BlockMove(pb->bufptr->dataptr, bufptr->dataptr, (long) bufptr->length);
  530.             pb->bufptr = bufptr;
  531.             /* prime lcp echo routine */
  532.             PrimeTime(&(lap->echo_task), (long)lap->prefdata.echo * 1000L);
  533.             return pb;
  534.         }
  535.     } else {
  536.         if ((ipb = pb->ipbuf) == nil) {    /* shouldn't happen */
  537.             PPP_DEBUG_CHECKS("\pip buffer ptr nil");
  538.             return nil;
  539.         }
  540.         
  541.         if ((bufptr = getbuffer()) == nil){    /* get a buffer */
  542.             IOfinish(lap, pb);
  543.             return nil;
  544.         }
  545.         wdsp = &(ipb->ip);        /* point to wds entries (@ip header) */
  546.         datap = bufptr->dataptr;
  547.  
  548.         /* copy packet into a buffer */
  549.     
  550.         while ( (n = wdsp->length) != 0 ) {
  551.             BlockMove(wdsp->ptr, datap, (long) n);
  552.             bufptr->length += n;
  553.             datap += n;
  554.             wdsp++;
  555.         }
  556.         tcp_window_fix(lap, bufptr);    /* chop down TCP window size */
  557.  
  558.         if (lap->ipcp_i.remote.work_negotiate & IPCP_N_COMPRESS) {
  559.             /* Attempt IP/TCP header compression */
  560.             switch (slhc_compress(lap, bufptr,
  561.                          lap->ipcp_i.remote.work.ipcp_option.slot_compress)) {
  562.             case SL_TYPE_IP:
  563.                 protocol = PPP_IP_PROTOCOL;
  564.                 break;
  565.             case SL_TYPE_COMPRESSED_TCP:
  566.                 protocol = PPP_COMPR_PROTOCOL;
  567.                 break;
  568.             case SL_TYPE_UNCOMPRESSED_TCP:
  569.                 protocol = PPP_UNCOMP_PROTOCOL;
  570.                 break;
  571.             default:
  572.                 lap->OutError++;
  573.                 PPP_DEBUG_CHECKS("\pVJ compress error");
  574.                 release(bufptr);
  575.                 IOfinish(lap, pb);
  576.                 return nil;
  577.             }
  578.         }
  579.         if (lap->ppp_phase == pppDEAD) {
  580.             lap->OutError++;
  581.             PPP_DEBUG_CHECKS("\pDead link output error");
  582.             release(bufptr);
  583.             IOfinish(lap, pb);
  584.             return nil;
  585.         }
  586.  
  587.         htonppp(lap, protocol, bufptr);
  588.         pb->bufptr = bufptr;
  589.     }
  590.     return pb;        /* pointer to transmit iopb */
  591. }
  592.  
  593. /* routine to transmit some characters from the transmit fifo
  594.  * This is executed as part of the transmit IO completion routine.
  595.  * TXBUFSIZE controls the maximum number of characters to transmit.
  596.  * Don't make this too large as it may result in receive overruns
  597.  * because this will often be executed during level 2 interrupt time.
  598.  */
  599. void    xmitout(register LapInfo *lap)
  600. {
  601.     register Byte *outptr = lap->outbuf;
  602.     register Byte *outmax = outptr + TXBUFSIZE; /* make comparison faster*/
  603.     register long qindex = lap->XmitQHead;
  604.     register ioParam *iop = &(lap->w_iopb.iop);
  605.     
  606.     if (lap->ok_to_xmit && (lap->XmitQSize > 0)) {
  607.         lap->ok_to_xmit = false;
  608.         do  {
  609.             *outptr++ = lap->XmitQ[qindex++];
  610.             qindex &= (XMITQLEN - 1);
  611.         } while ( ( --(lap->XmitQSize) != 0 ) && (outptr < outmax) );
  612.         
  613.         lap->XmitQHead = qindex;
  614.         iop->ioBuffer = lap->outbuf;
  615.         iop->ioReqCount = outptr - lap->outbuf;
  616.         if (noErr != PBWrite(iop,true)) {
  617.             lap->writerr++;
  618.             PPP_DEBUG_CHECKS("\pxmitout: error");
  619.         }
  620.     }
  621. }
  622.  
  623. /* routine to place some chars in the transmit fifo */
  624. void    xmitfifo(register LapInfo *lap, short len)
  625. {
  626.     short    sreg;
  627.     short    i;
  628.     register Byte    *bufptr = lap->xbuf;
  629.     
  630.     for    ( i = 0 ; i < len ; ++i ) {
  631.         if (lap->XmitQSize >= XMITQLEN) {
  632.             PPP_DEBUG_CHECKS("\pOverflowed xmit fifo");    /* this shouldn't happen */
  633.             break;            
  634.         }
  635.         lap->XmitQ[lap->XmitQTail++] = *bufptr++;
  636.         lap->XmitQTail &= (XMITQLEN - 1);
  637.         lap->XmitQSize++;
  638.     }
  639.     xmitout(lap);            /* try to xmit some characters in the fifo */
  640. }
  641.  
  642. /*
  643. *    This is the serial write i/o completion routine.  All it does is call
  644. *    the xmitout routine to transmit some chars from the fifo.
  645. */
  646. ProcPtr hdlcwioc()
  647. {
  648. register LapInfo *lap;
  649. sdiopb        *pb;
  650. short        sreg;
  651.  
  652.     /*  We are allowed to trash a0,a1,d0-d2 */
  653.     asm {
  654.         move.l a0,pb             ; set up paramblkptr
  655.         };
  656.     
  657.     lap = pb->lap;
  658.  
  659.     if (pb->iop.ioActCount > pb->iop.ioReqCount) {
  660.         lap->writerr++;
  661.         PPP_DEBUG_CHECKS("\pwrite: Tx berserk");
  662.     }
  663.         
  664.     if (pb->iop.ioResult != noErr) {
  665.         PPP_DEBUG_CHECKS("\pWrite error");
  666.         lap->writerr++;    /* count bad writes */
  667.     }
  668.     
  669.     lap->OutTxOctetCount += pb->iop.ioActCount;    /* add to total out count */
  670.     lap->ok_to_xmit = true;        /* okay to transmit some more */
  671.     xmitout(lap);     /* transmit some more bytes */
  672. }
  673.  
  674. void    ProcXmtPPP(void)
  675. {
  676. register LapInfo    *lap;
  677. struct TMprocess    *tmprocp;
  678. register int        XmitByte;
  679. short                xlen;
  680. ProcPtr                ioc;
  681. register HDLCState    wstate;
  682. PPPiopb                *pb;
  683. register char        *xbufp;
  684.  
  685.     asm    {
  686.         move.l    a1,tmprocp
  687.     };
  688.     
  689.     lap = tmprocp->tmsavptr.lap;
  690.  
  691.     /* we loop through this routine until either it is done handling the
  692.     output or the xmit fifo is too full. In the latter case, we re-prime the
  693.     routine to execute later (when there is more room in the fifo)
  694.     */
  695.     while (TRUE) {
  696.         if ( lap->XmitQSize > (XMITQLEN - 8) ) {
  697.             if (!(lap->txp_task.atm.qType & TASK_QUEUED))    /* check if task in q */
  698.                 PrimeTime(&(lap->txp_task), 18L);
  699.             break;
  700.         }
  701.  
  702.     /* Normally, a switch() would be used here, but its painfully slow.
  703.      * Instead, we use a carefully ordered if...elseif...elseif to speed
  704.      * up the transmitter.
  705.      */
  706.         wstate = lap->write_state;    /* put in register for speed */
  707.         if (wstate == s_Data) {    /* we're in the middle of a packet */
  708.             if ((XmitByte = yankbyte(lap->active->bufptr)) == -1 ) {/* get byte */
  709.                 lap->write_state = s_SendFCS;    /* move to FCS state */
  710.                 release(lap->active->bufptr);
  711.                 lap->active->bufptr = nil;
  712.             } else {
  713.                 lap->XmitFCS = pppfcs(lap->XmitFCS, XmitByte);
  714.                 xlen = 1;
  715.                 /* escape ESC, FLAG, and all characters in escape map */
  716.                    if (((XmitByte < 0x20) && (lap->PPP_activeACM & (1L << XmitByte)))
  717.                   ||  (XmitByte == PPP_FLAG) || (XmitByte == PPP_ESCAPE)) {
  718.                     lap->xbuf[0] = PPP_ESCAPE;    /* send ESC */
  719.                       lap->xbuf[1] = (Byte) XmitByte ^ 0x20;    /* encoded character */
  720.                     xlen++;
  721.                 } else
  722.                     lap->xbuf[0] = (Byte) XmitByte;   /* un-escaped character */
  723.                 xmitfifo(lap, xlen);    /* fifo the data */
  724.             }
  725.         } else if (wstate == s_Idle) {        /* just sitting around */
  726.             if (lap->active == nil ) { 
  727.                 if ((lap->active = Getxmitpb(lap)) != nil) {
  728.                     /* something on queue */
  729.                     if (lap->active->ipbuf == nil) /* LCP and NCP always escaped */
  730.                         lap->PPP_activeACM = 0xFFFFFFFFL;
  731.                     else
  732.                         lap->PPP_activeACM = lap->PPP_XmitACM; /* use current ACCM */
  733.                     lap->write_state = s_Data;
  734.                     lap->OutOpenFlag++;        /* about to send an open flag */
  735.                     lap->XmitFCS = FCS_INIT;    /* start new FCS calculation */
  736.                     if (lap->ok_to_xmit) { /* see if already xmitting */
  737.                         lap->xbuf[0] = PPP_FLAG; /* no, so send a flag */
  738.                         xmitfifo(lap, 1); 
  739.                     }
  740.                 } else 
  741.                     break;
  742.             } else {
  743.                 lap->OutError++;
  744.                 PPP_DEBUG_CHECKS("\pIdle: active tx buffer");
  745.                 lap->write_state = s_Finish;
  746.             }
  747.         } else if (wstate == s_SendFCS) {     /* Packet is done */
  748.             lap->write_state = s_Finish;    /* done with pkt  */
  749.  
  750.         /* The FCS is complemented before transmitting.  It is also
  751.         *  transmitted low byte first, then high byte, which is a real
  752.         *  pain in the butt.
  753.         */
  754.             lap->XmitFCS ^= 0xffff;        /* send one's compl. */
  755.             xbufp = lap->xbuf;
  756.             XmitByte = lap->XmitFCS & 0xFF;
  757.             if ( ( ( XmitByte < 0x20 ) && ( lap->PPP_activeACM & ( 1L << XmitByte ) ) ) ||
  758.             ( XmitByte == PPP_FLAG ) || ( XmitByte == PPP_ESCAPE ) ) {
  759.                 *xbufp++ = PPP_ESCAPE;
  760.                 XmitByte ^= 0x20;
  761.             }
  762.             *xbufp++ = (Byte) XmitByte;
  763.  
  764.             /* do hi FCS byte */
  765.             XmitByte = lap->XmitFCS >> 8;
  766.             if ( ( ( XmitByte < 0x20 ) && ( lap->PPP_activeACM & ( 1L << XmitByte ) ) ) ||
  767.             ( XmitByte == PPP_FLAG ) || ( XmitByte == PPP_ESCAPE ) ) {
  768.                 *xbufp++ = PPP_ESCAPE;
  769.                 XmitByte ^= 0x20;
  770.             }
  771.             *xbufp++ = (Byte) XmitByte;
  772.  
  773.             /* do closing flag */
  774.  
  775.             *xbufp++ = PPP_FLAG;
  776.             xlen = xbufp - lap->xbuf;
  777.             xmitfifo(lap, xlen);  /* send it along */
  778.             
  779.         } else if (wstate == s_Finish) {        /* ending FLAG has been sent */
  780.         /*
  781.         *  If the buffer just sent was an IP datagram, let the
  782.         *  IP layer know we finished the write.
  783.         */
  784.             pb = lap->active;        /* store pointer to current iopb */
  785.             lap->active = nil;        /* make current nil */
  786.             lap->write_state = s_Idle;    /* Idle state */
  787.             if ( pb->ipbuf != nil) {
  788.                 pb->ipbuf->iop.ioResult = noErr;    /* i/o is complete */
  789.                 IOfinish(lap, pb); /* call completion routine */
  790.             } else {
  791.                 /* 
  792.                 *  not an IP packet, just put iopb on free queue.
  793.                 */
  794.                 Enqueue(pb, &(lap->pppbq));    /* put on free Q */
  795.             }        
  796.         } else if (wstate == s_Init)
  797.             break;
  798.         else  {
  799.             lap->OutError++;
  800.             PPP_DEBUG_CHECKS("\pPPP Tx: bad state");
  801.         }
  802.     }
  803. }
  804.